package menus.flower.recognizers;

import java.awt.geom.Point2D;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.PriorityQueue;

import menus.common.AbstractGestureAnalyzer;

import fr.lri.swingstates.gestures.Gesture;

/**
 * Class used to recognize user-drawn gestures in a Flower Menu. 
 * The method used is a k-nearest-neighbor with simple gesture data.  
 * 
 * @author mathieu
 *
 */
public class MyFlowerGestureRecognizer extends AbstractFlowerGestureRecognizer {
	
	/**
	 * Name of the file containing the gesture base
	 */
	protected String gestureBaseFileName = "../AverageGestureData.csv";
	
	/**
	 * Gesture base. A gesture is represented by :
	 * 	<ul>
	 * 		<li>An ID</li>
	 * 		<li>A start angle</li>
	 * 		<li>An end angle</li>
	 * 		<li>A rotating direction</li>
	 * 	</ul>
	 */
	protected double[][] gestureBase;
	
	/**
	 * true if the gesture base already have been extracted, false otherwise
	 */
	protected boolean baseExtracted = false;
	
	
	
	// ----------------------------------------------------------------- XXX

	
	public MyFlowerGestureRecognizer(HashSet<Integer> availableItemIDs){
		super(availableItemIDs);
	}
	
	public MyFlowerGestureRecognizer(HashSet<Integer> availableItemIDs, String gestureBase){
		super(availableItemIDs);
		this.gestureBaseFileName = gestureBase;
	}
	
	
	
	protected double computeScore(double[] userGesture, double[] baseGesture){
		
		// Directly opposed rotating directions : can't be this gesture
		if (userGesture[ROT_DIRECTION] * baseGesture[ROT_DIRECTION] == -1)
			return 10000;
		
		return 10 * (range2PI(userGesture[START_ANGLE]) - range2PI(baseGesture[START_ANGLE])) * (range2PI(userGesture[START_ANGLE]) - range2PI(baseGesture[START_ANGLE]))
				+ (range2PI(userGesture[END_ANGLE]) - range2PI(baseGesture[END_ANGLE])) * (range2PI(userGesture[END_ANGLE]) - range2PI(baseGesture[END_ANGLE]));
		
	}
	
	public int recogniseGesture(Gesture gesture){
		
		double[] gestureData = analyzeGesture(gesture);
		
		// Classifying the base gestures (low-cost operation)
		
		PriorityQueue<double[]> best = new PriorityQueue<double[]>(gestureBase.length, new Comparator<double[]>(){
			public int compare(double[] o1, double[] o2) {
				return new Double(o1[SCORE]).compareTo(o2[SCORE]);
			}
		});
		
		for (double[] baseGesture : gestureBase){
			
			if (baseGesture != null){
				if (!availableItemIDs.contains((int)baseGesture[ID])){
					continue;
				}
				
				baseGesture[SCORE] = computeScore(gestureData, baseGesture);
				best.offer(baseGesture);
			}
		}
		
		// Retrieving the best one
		
		return (int)best.poll()[ID];
		
	}
	
	public void extractGestureBase(){
		
		double[][] result = new double[56][]; 
		
		String ligne;
		String[] parts;
		
		int it = 0;
		
		try {
			BufferedReader reader = new BufferedReader(new FileReader(this.gestureBaseFileName));
			
			reader.readLine(); // Headers
			
			while( (ligne = reader.readLine()) != null && !ligne.equals("")){
				parts = ligne.split(";"); // TODO check
				
				double[] baseGesture = new double[5];
				for (int i = 0; i < 4; i++){
					baseGesture[i] = new Double(parts[i].replace(',', '.'));
				}
				
				result[it] = baseGesture;
				it++;
			}
			
			gestureBase = result;
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		}
		
	}
	
	public void extractGestureBase(String fileName){
		this.gestureBaseFileName = fileName;
		extractGestureBase();
	}
	
	public double range2PI(double arg){
		return (arg + 2 * Math.PI) % (2 * Math.PI);
	}
	
	
	
}
